/*
 * This program is free software: you can redistribute it and/or modify it under
 * the terms of the GNU General Public License as published by the Free Software
 * Foundation, either version 3 of the License, or (at your option) any later
 * version.
 *
 * This program is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
 * details.
 *
 * You should have received a copy of the GNU General Public License along with
 * this program. If not, see <http://www.gnu.org/licenses/>.
 */package org.merak.core.text;

import java.lang.reflect.Method;
import java.util.Date;
import java.util.Enumeration;
import java.util.Map;

/**
 * Copyright © 2010-2012 Merak Computing. All rights reserved.<br><br>
 *
 * Methods and declarations for Control.
 *
 * @author fmarinho.
 * @version 1.00.00 - Jul 20, 2012 - fmarinho - initial version.
 *
 * @since MerakCore 1.00.00
 */
public final class Control {

	//~ Attributes ///////////////////////////////////////////////////////////////
	//****************************************************************************
	private final TextifierSet set = new TextifierSet();

	//~ Methods //////////////////////////////////////////////////////////////////
	//****************************************************************************
	/**
	 * Returns the Textifier specialized in serializing the provided class.
	 * @param clazz The class of objects to be serialized.
	 * @since 1.00.00
	 */
	private Textifier<?> choose(Class<?> clazz) {

		// If class is Raw Type
		if ( Number.class.isAssignableFrom(clazz)      ) return this.set.getNumberTextifier();
		if ( CharSequence.class.isAssignableFrom(clazz)) return this.set.getStringTextifier();
		if ( clazz.isEnum()                            ) return this.set.getEnumTextifier();
		if ( Boolean.class.isAssignableFrom(clazz)     ) return this.set.getBooleanTextifier();
		if ( Date.class.isAssignableFrom(clazz)        ) return this.set.getDateTextifier();
		if ( Character.class.isAssignableFrom(clazz)   ) return this.set.getCharacterTextifier();

		// If class is a Group Type
		if ( clazz.isArray()                          ) return this.set.getArrayTextifier();
		if ( Iterable.class.isAssignableFrom(clazz)   ) return this.set.getIterableTextifier();
		if ( Map.class.isAssignableFrom(clazz)        ) return this.set.getMapTextifier();
		if ( Enumeration.class.isAssignableFrom(clazz)) return this.set.getEnumerationTextifier();

		// If class is a special case
		if ( Void.class.isAssignableFrom(clazz) ) return this.set.getNullTextifier();

		// Any other type will be handled as object
		return this.set.getObjectTextifier();

	}
	//****************************************************************************
	/**
	 * Returns the Textifier specialized in serializing the provided object.
	 * @param object The object to be serialized.
	 * @since 1.00.00
	 */
	@SuppressWarnings("unchecked")
	private Textifier<Object> chooseTextifier(Object object) {

		return (Textifier<Object>) ((object == null)
				? this.set.getNullTextifier()
				: this.choose(object.getClass()));

	}
	//****************************************************************************
	/**
	 * Returns the Textifier specialized in serializing objects of provided class.
	 * @param clazz The class whose object(s) will be serialized.
	 * @since 1.00.00
	 */
	@SuppressWarnings({ "unchecked", "unused" })
	private Textifier<Object> chooseTextifier(Class<?> clazz) {

		return (Textifier<Object>) ((clazz == null)
				? this.set.getNullTextifier()
				: this.choose(clazz));

	}
	//****************************************************************************
	/**
	 * Returns the Textifier specialized in serializing objects of returned by the method.
	 * @param method The method whose returned object will be serialized.
	 * @since 1.00.00
	 */
	@SuppressWarnings({ "unchecked", "unused" })
	private Textifier<Object> chooseTextifier(Method method) {

		return (Textifier<Object>) ((method == null)
				? this.set.getNullTextifier()
				: this.choose( method.getReturnType() ));

	}
	//****************************************************************************
	/**
	 * Returns the set of textifiers used in this controller.
	 * @since 1.00.00
	 */
	public TextifierSet getTextifiers() {
		return this.set;
	}
	//****************************************************************************
	@SuppressWarnings("unchecked")
	public void execute(CharSequence value,Context context) throws Exception {

		try {
			Textifier<CharSequence> t = (Textifier<CharSequence>) this.set.getStringTextifier();
			t.textify(value,context);
		}
		catch (Exception e) {
			// Make sure to clean the buffer
			context.readAndClear();
			throw e;
		}

	}
	//****************************************************************************
	public void execute(Object value,Context context) throws Exception {

		try {
			this.chooseTextifier(value).textify(value,context);
		}
		catch (Exception e) {
			// Make sure to clean the buffer
			context.readAndClear();
			throw e;
		}

	}
	//****************************************************************************
	public void execute(Object object,Method getter,Context context) throws Exception {

		try {
			// Execute the getter to retrieve the value
			Object value = getter.invoke(object);
			// Choose the textifier based on the result type
			this.chooseTextifier(value).textify(value,context);
		}
		catch (Exception e) {
			// Make sure to clean the buffer
			context.readAndClear();
			throw e;
		}

	}
	//****************************************************************************

}
